﻿using System;
using System.Data;
using System.Text;
using System.Windows.Forms;
using SdmxMl.Structure;
using SdmxMl.Manager;
using SdmxMl.Common;
using SdmxMl.GenericMetadata;

namespace SdmxMl.UC
{
    #region Enum

    /// <summary>
    /// Internal type edition associated to special control
    /// </summary>
    enum TypeEdit
    {
        BigStringML,
        ShortStringML,
        StringUntranslated,
        Code,
        MultiCode,
        Numeric,
        Others
    }
    #endregion // Enum

    /// <summary>
    /// Edit control adapted to meta information
    /// </summary>
    public partial class UcAttributeEditControl : UserControl
    {
        #region Internal Members

        private TypeEdit editType;
        private bool inSetting;
        private IReportedValue metadataVal;
        private TextFormatType _textFormat;
        private TextFormatType _textFormatUndefined;
        private bool IsPresentational;

        #endregion // Internal Members

        public bool IsFinal { get; set; }

        #region Construction

        public UcAttributeEditControl()
        {
            InitializeComponent();
            editType = TypeEdit.Others;
            _textFormatUndefined = new TextFormatType();
            buttonNavigateUrn.Visible = false;
        }
        #endregion // Construction

        #region AttachValue

        public IReportedValue MetaDataValue
        {
            set
            {
                metadataVal = value;

                //Retrieve value string
                string txt = metadataVal.SimpleValue;
                if (metadataVal.InternationalizedValue != null)
                    txt = metadataVal.InternationalizedValue.IsEmpty ? string.Empty : metadataVal.InternationalizedValue.ToString();
                if (txt == null)
                    txt = string.Empty; // ensure empty string in case of missing content

                switch (editType)
                {
                    case TypeEdit.Code:
                        if (txt.Length > 0)
                            multiColumnCombo.Text = txt;
                        multiColumnCombo.Enabled = IsFinal == false;
                        break;

                    case TypeEdit.MultiCode:
                        if (txt.Length > 0)
                        {
                            string[] arr = txt.Split(';');
                            foreach (string s in arr)
                            {
                                for (int i = 0; i < checkedListBox.Items.Count; ++i)
                                {
                                    ISdmxHierarchyListItem item = checkedListBox.Items[i] as ISdmxHierarchyListItem;
                                    if (item != null && item.Id == s)
                                    {
                                        checkedListBox.SetItemChecked(i, true);
                                        break;
                                    }
                                }
                            }
                            checkedListBox.Enabled = IsFinal == false;
                        }
                        break;

                    case TypeEdit.BigStringML:
                        BigMultiLang.IsFinal = IsFinal;
                        BigMultiLang.ML = metadataVal.InternationalizedValue;
                        break;

                    case TypeEdit.Numeric:
                        numTextBox.Text = txt;
                        numTextBox.ReadOnly = IsFinal;
                        break;

                    case TypeEdit.StringUntranslated:
                        textBox.Text = txt;
                        textBox.ReadOnly = IsFinal;
                        break;

                    default:
                        break;
                }

            }
        }

        #endregion // AttachValue

        #region Bind MetaInformation

        public void BindReferedConcept(ConceptType concept, IHierarchyManage ihm, TextFormatType tft, bool multiCodes, bool isPresentational)
        {
            CodeListType codeList = null;
            FlatHierarchicalList flatList = ihm as FlatHierarchicalList;
            this.IsPresentational = isPresentational;
            _textFormat = (tft == null) ? _textFormatUndefined : tft;

            if (!this.IsPresentational)
            {
                // Usage of codelist from data or from concept (if any)
                if (flatList == null && concept != null && concept.CoreRepresentation.Id.Length > 0)
                {
                    codeList = ReferenceManager.LocateCodelist(concept.CoreRepresentation);
                    flatList = codeList.CodeList;
                }

                if (flatList != null)
                {
                    if (multiCodes)
                        SetMultiCodesCheckList(flatList);
                    else
                        SetMultiColumnCombo(flatList.GetTableRepresentation());
                }
                else if (ihm != null)
                    SetMultiColumnCombo(ihm.GetTableRepresentation());

                else
                {
                    // Retrieve Textformat of concept if not specified in meta
                    if (concept != null && _textFormat.TextType == TextTypeType.Undefined)
                        _textFormat = concept.TextFormat;

                    // Control according to text format
                    if (_textFormat.IsNumeric)
                        SetNumeric();
                    else if (tft != null && _textFormat.IsMultiLang)
                        SetMultiLangBig();
                    else
                        SetSingleLang();
                }
            }

            HideControls();
        }

        #endregion // Bind MetaInformation

        #region Enable selected Edit Control

        /// <summary>Hides controls of edition that are not targeted. </summary>
        private void HideControls()
        {

            if (editType != TypeEdit.BigStringML || IsPresentational)
                BigMultiLang.Visible = false;

            if (editType != TypeEdit.Code || IsPresentational)
            {
                multiColumnCombo.Visible = false;
                textBoxCodeDescription.Visible = false;
            }

            if (editType != TypeEdit.MultiCode || IsPresentational)
                checkedListBox.Visible = false;

            if (editType != TypeEdit.Numeric || IsPresentational)
                numTextBox.Visible = false;

            if (editType != TypeEdit.StringUntranslated || IsPresentational)
            {
                textBox.Visible = false;
                buttonNavigateUrn.Visible = false;
            }
        }

        /// <summary>
        /// Edit control for text without translation (not multi language)
        /// </summary>
        private void SetSingleLang()
        {
            editType = TypeEdit.StringUntranslated;
            textBox.Visible = true;
            if (_textFormat.TextType == TextTypeType.URI)
                buttonNavigateUrn.Visible = true;

            if (_textFormat.TextType == TextTypeType.String)
            {
                textBox.Multiline = true;
                textBox.Height = this.Height;
            }
            else
            {
                textBox.Multiline = false;
            }
        }

        /// <summary>
        /// Edit control for multi languages text
        /// </summary>
        private void SetMultiLangBig()
        {
            editType = TypeEdit.BigStringML;
            BigMultiLang.Visible = true;
            BigMultiLang.Width = this.Width;
            BigMultiLang.Height = this.Height;
        }

        /// <summary>
        /// Edit control for numeric fields
        /// </summary>
        private void SetNumeric()
        {
            editType = TypeEdit.Numeric;
            numTextBox.Visible = true;
            switch (_textFormat.TextType)
            {
                case TextTypeType.Decimal:
                    numTextBox.InputType = NumEditType.Decimal;
                    break;

                case TextTypeType.Short:
                    numTextBox.InputType = NumEditType.SmallInteger;
                    break;

                case TextTypeType.Integer:
                case TextTypeType.Count:
                    numTextBox.InputType = NumEditType.Integer;
                    break;

                case TextTypeType.Float:
                case TextTypeType.Double:
                    numTextBox.InputType = NumEditType.Double;
                    break;

                case TextTypeType.BigInteger:
                    numTextBox.InputType = NumEditType.LargeInteger;
                    break;
            }
            numTextBox.Visible = true;
        }

        /// <summary>
        /// Edit controls for codelist selection
        /// </summary>
        /// <param name="codeList"></param>
        private void SetMultiColumnCombo(DataTable tb)
        {
            inSetting = true;

            editType = TypeEdit.Code;
            multiColumnCombo.Visible = true;
            textBoxCodeDescription.Visible = true;
            multiColumnCombo.ValueMember = "Code";
            multiColumnCombo.DisplayMember = "Code";
            multiColumnCombo.ColumnNames = "Code;Description";
            multiColumnCombo.DataSource = tb;
            multiColumnCombo.ColumnWidths = (multiColumnCombo.Width).ToString() + ";" + this.textBoxCodeDescription.Width.ToString();
            multiColumnCombo.Text = null;
            multiColumnCombo.DropDownWidth = multiColumnCombo.Width + this.textBoxCodeDescription.Width;

            inSetting = false;
        }

        private void SetMultiCodesCheckList(FlatHierarchicalList flh)
        {
            inSetting = true;

            editType = TypeEdit.MultiCode;
            checkedListBox.Items.Clear();
            checkedListBox.Visible = true;
            checkedListBox.Height = this.Height;
            foreach (ISdmxHierarchyListItem item in flh)
                checkedListBox.Items.Add(item);
            inSetting = false;
        }
        #endregion //Enable selected Edit Control

        #region Controls Events

        private void multiColumnCombo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (inSetting)
                return;

            UpdateValue(multiColumnCombo.Text);
        }

        private void numTextBox_TextChanged(object sender, EventArgs e)
        {
            UpdateValue(numTextBox.Text);
        }

        private void textBox_TextChanged(object sender, EventArgs e)
        {
            UpdateValue(textBox.Text);

        }

        /// <summary>
        /// Update according to internationalized or not
        /// </summary>
        /// <param name="value">new value to fill</param>
        private void UpdateValue(string value)
        {
            if (metadataVal != null)
            {
                if (metadataVal.InternationalizedValue != null)
                    metadataVal.InternationalizedValue.UpdateDefaultText(value);
                else
                    metadataVal.SimpleValue = value;
            }
        }

        /// <summary>
        /// All checked items are concatenated separated by semi-column
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (inSetting)
                return;

            StringBuilder sb = new StringBuilder();
            int itemIndex = e.Index;
            ISdmxHierarchyListItem curItem = checkedListBox.Items[itemIndex] as ISdmxHierarchyListItem;
            foreach (ISdmxHierarchyListItem item in checkedListBox.CheckedItems)
            {
                if (item == curItem)
                {
                    if (e.NewValue == CheckState.Unchecked)
                        continue;
                }
                else
                {
                    if (sb.Length > 0)
                        sb.Append(';');
                    sb.Append(item.Id);
                }
            }

            if (e.NewValue == CheckState.Checked)
            {
                if (sb.Length > 0)
                    sb.Append(';');
                sb.Append(curItem.Id);
            }
            UpdateValue(sb.ToString());
        }

        #endregion //Controls Events

        #region URI Navigation

        private void buttonNavigateUrn_Click(object sender, EventArgs e)
        {
            if (_textFormat != null && _textFormat.TextType == TextTypeType.URI)
            {
                TextBox tb = this.textBox;
                if (tb != null && tb.Text.Length > 0)
                {
                    UrnParser up = new UrnParser(tb.Text);
                    if (up.IsSupported)
                    {
                        try
                        {
                            // If URN try to get it if not already in memory
                            ArtefactRefTyped art = new ArtefactRefTyped(
                                up.ArType, up.ArtefactId, up.AgencyId, up.Version);
                            if (art != null)
                            {
                                // If already in memory, navigate otherwhile get from regidtry
                                if (NavigationManager.LocatenavigateProject(art.Type, art.FullIdent, up) == null)
                                    NavigationManager.NavigateWithRegistry(art.Type, art.FullIdent, true, up);
                            }
                        }

                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message, "Error");
                        }

                    }
                }
            }

        }
        #endregion



    }
}
